package com.h3c.ptability.service;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.h3c.it.common.misc.model.PageableQuery;
import com.h3c.it.common.web.model.ResponseObject;
import com.h3c.ptability.bo.GetUserByDeptAndRoleBO;
import com.h3c.ptability.cache.EosTokenCache;
import com.h3c.ptability.dto.eos.EosRoleClientDTO;
import com.h3c.ptability.dto.eos.EosUserClientDTO;
import com.h3c.ptability.dto.eos.UserRoleDTO;
import com.h3c.ptability.entity.PtAllWorker;
import com.h3c.ptability.entity.PtApp;
import com.h3c.ptability.entity.PtRoleUser;
import com.h3c.ptability.entity.PtUserDept;
import com.h3c.ptability.mapper.PtRoleUserMapper;
import com.h3c.ptability.utils.AppBusinessException;
import com.h3c.ptability.utils.CommonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: yys44482
 * @Date: 2022/7/20
 */
@Service
@Slf4j
public class EosAuthService {

    @Autowired
    CommService commService;

    @Autowired
    IPtAllWorkerService ptAllWorkerService;

    @Autowired
    IPtAppService ptAppService;

    @Autowired
    IPtUserDeptService ptUserDeptService;

    @Resource
    PtRoleUserMapper roleUserMapper;

    @Value("${eosAPassAccount}")
    private String eosAPassAccount;
    @Value("${eosAPassPasswd}")
    private String eosAPassPasswd;

    @Value("${eos.getRoleList.url}")
    private String getRoleListUrl;

    @Value("${eos.getUserList.url}")
    private String getUserListUrl;

    @Value("${eos.updateUserRole.url}")
    private String updateUserRoleUrl;

    @Value("${eos.deleteUserRole.url}")
    private String deleteUserRoleUrl;

    @Value("${eos.queryUserRoleByAccount.url}")
    private String queryUserRoleByAccount;

    @Value("${eos.getRolesByAccount.url}")
    private String getRolesByAccountUrl;

    public List<EosRoleClientDTO> getRoleList(String query, String appId, Integer currentPage, Integer pageSize, String account) {
        PtApp ptApp = ptAppService.getById(appId);
        Assert.notNull(ptApp, () -> {
            throw new AppBusinessException("不存在此应用");
        });
        String eosToken = commService.getAuthenticationCenterToken(eosAPassAccount, eosAPassPasswd);
        HashMap<String, Object> params = new HashMap<>(3);
        params.put("query", query);
        params.put("pageNum", currentPage);
        params.put("pageSize", pageSize);
        String eosRes = HttpRequest.get(getRoleListUrl)
                .form(params)
                .header("Authorization", eosToken)
                .header("Eos-Project", ptApp.getAuthCenterId())
                .execute().body();
        ResponseObject<PageableQuery<String, EosUserClientDTO>> res =
                JSON.parseObject(eosRes, new TypeReference<ResponseObject<PageableQuery<String, EosUserClientDTO>>>() {
                });
        if (res.getCode() != 0) {
            log.error("获取角色失败=============================================");
            log.error(res.getMsg());
            log.error(res.getTechMsg());
            log.error("====获取角色失败=============================================");
            throw new AppBusinessException("");
        }
        List<EosRoleClientDTO> roleClientDTOS = JSONArray.parseArray(JSONArray.toJSONString(res.getData().getList()), EosRoleClientDTO.class);
        roleClientDTOS = roleClientDTOS.stream().filter(s -> !"AUTH_INITIAL_ADMIN".equals(s.getRoleCode())).collect(Collectors.toList());
        if ("hrdataboard".equals(appId)) {
            return roleClientDTOS.stream().filter(s -> s.getRoleCode().contains("budget")).collect(Collectors.toList());
        } else if ("hr-dynamic-board".equals(appId)) {
            return roleClientDTOS.stream().filter(s -> s.getRoleCode().contains("dynamic")).collect(Collectors.toList());
        } else if ("e-sign-platform".equals(appId)) {
            List<String> roles = getUserRoleByAccount(account, appId);
            boolean isSSC = false;
            for (String role : roles) {
                if (role.equals("SSC-SIGN")) {
                    isSSC = true;
                    break;
                }
            }
            if (!isSSC) {
                List<PtRoleUser> ptRoleUsers = roleUserMapper.selectList(new QueryWrapper<PtRoleUser>().lambda()
                        .eq(PtRoleUser::getAppId, appId)
                        .eq(PtRoleUser::getDomainAccount, account));
                return roleClientDTOS.stream().filter((s) -> {
                    boolean match = false;
                    for (PtRoleUser roleUser : ptRoleUsers) {
                        if (roleUser.getRoleId().equals(s.getRoleCode())) {
                            match = true;
                            break;
                        }
                    }
                    return match;
                }).collect(Collectors.toList());
            }
        }
        return roleClientDTOS;
    }


    public List<EosUserClientDTO> getUserListByRoleCode(String roleCode, String appId, Integer currentPage, Integer pageSize) {
        PtApp ptApp = ptAppService.getById(appId);
        Assert.notNull(ptApp, () -> {
            throw new AppBusinessException("不存在此应用");
        });
        String eosToken = commService.getAuthenticationCenterToken(eosAPassAccount, eosAPassPasswd);
        HashMap<String, Object> params = new HashMap<>(4);
        params.put("pageNum", currentPage);
        params.put("pageSize", pageSize);
        params.put("roleCode", roleCode);
        params.put("searchType", 0);
        String eosRes = HttpRequest.get(getUserListUrl)
                .form(params)
                .header("Authorization", eosToken)
                .header("Eos-Project", ptApp.getAuthCenterId())
                .execute().body();
        ResponseObject<PageableQuery<String, EosUserClientDTO>> res =
                JSON.parseObject(eosRes, new TypeReference<ResponseObject<PageableQuery<String, EosUserClientDTO>>>() {
                });
        if (res.getCode() != 0) {
            log.error("获取角色下用户失败=============================================");
            log.error(res.getMsg());
            log.error(res.getTechMsg());
            log.error("====获取角色下用户失败=============================================");
            throw new AppBusinessException("");
        }
        return JSONArray.parseArray(JSONArray.toJSONString(res.getData().getList()), EosUserClientDTO.class);
    }

    public List<EosUserClientDTO> getUserListByRoleCode(String roleCode, String appId, String eosToken, HashMap<String, Object> params) {
        PtApp ptApp = ptAppService.getById(appId);
        Assert.notNull(ptApp, () -> {
            throw new AppBusinessException("不存在此应用");
        });
        params.put("roleCode", roleCode);
        String eosRes = HttpRequest.get(getUserListUrl)
                .form(params)
                .header("Authorization", eosToken)
                .header("Eos-Project", ptApp.getAuthCenterId())
                .execute().body();
        ResponseObject<PageableQuery<String, EosUserClientDTO>> res =
                JSON.parseObject(eosRes, new TypeReference<ResponseObject<PageableQuery<String, EosUserClientDTO>>>() {
                });
        if (res.getCode() != 0) {
            log.error("获取角色下用户失败=============================================");
            log.error(res.getMsg());
            log.error(res.getTechMsg());
            log.error("====获取角色下用户失败=============================================");
            throw new AppBusinessException("");
        }
        return JSONArray.parseArray(JSONArray.toJSONString(res.getData().getList()), EosUserClientDTO.class);
    }

    public List<EosUserClientDTO> getUserListByAppRoleCode(String roleCode, String appId, String query, Integer currentPage, Integer pageSize) {
        PtApp ptApp = ptAppService.getById(appId);
        Assert.notNull(ptApp, () -> {
            throw new AppBusinessException("不存在此应用");
        });
        String eosToken = commService.getAuthenticationCenterToken(eosAPassAccount, eosAPassPasswd);
        HashMap<String, Object> params = new HashMap<>(5);
        params.put("query", query);
        params.put("pageNum", currentPage);
        params.put("pageSize", pageSize);
        params.put("roleCode", roleCode);
        params.put("searchType", 0);
        String eosRes = HttpRequest.get(getUserListUrl)
                .form(params)
                .header("Authorization", eosToken)
                .header("Eos-Project", ptApp.getAuthCenterId())
                .execute().body();
        ResponseObject<PageableQuery<String, EosUserClientDTO>> res =
                JSON.parseObject(eosRes, new TypeReference<ResponseObject<PageableQuery<String, EosUserClientDTO>>>() {
                });
        if (res.getCode() != 0) {
            log.error("获取角色下用户失败=============================================");
            log.error(res.getMsg());
            log.error(res.getTechMsg());
            log.error("====获取角色下用户失败=============================================");
            throw new AppBusinessException("");
        }
        return JSONArray.parseArray(JSONArray.toJSONString(res.getData().getList()), EosUserClientDTO.class);
    }

    //    @NeedEosLog(value = "根据角色添加用户")
    public String updateUserRole(UserRoleDTO userRoleDTO) {
        PtApp ptApp = ptAppService.getById(userRoleDTO.getAppId());
        Assert.notNull(ptApp, () -> {
            throw new AppBusinessException("不存在此应用");
        });
        String eosToken = EosTokenCache.getAuthToken();
        String eosRes = HttpRequest.put(updateUserRoleUrl)
                .body(JSONUtil.toJsonStr(userRoleDTO))
                .header("Authorization", eosToken)
                .header("Eos-Project", ptApp.getAuthCenterId())
                .execute().body();
        log.info("鉴权中心根据角色添加用户,参数:{},返回:{}", JSONUtil.toJsonStr(userRoleDTO), eosRes);
        Integer code = JSONUtil.parseObj(eosRes).getInt("code");
        if (0 != code) {
            throw new AppBusinessException("通知eos添加用户失败");
        }
        return eosRes;
    }

    //    @NeedEosLog(value = "根据角色删除用户")
    public String deleteUserRole(UserRoleDTO userRoleDTO) {
        PtApp ptApp = ptAppService.getById(userRoleDTO.getAppId());
        Assert.notNull(ptApp, () -> {
            throw new AppBusinessException("不存在此应用");
        });
        String eosToken = EosTokenCache.getAuthToken();
        String eosRes = HttpRequest.delete(deleteUserRoleUrl)
                .body(JSONUtil.toJsonStr(userRoleDTO))
                .header("Authorization", eosToken)
                .header("Eos-Project", ptApp.getAuthCenterId())
                .execute().body();
        log.info("鉴权中心根据角色删除用户,参数:{},返回:{}", JSONUtil.toJsonStr(userRoleDTO), eosRes);
        Integer code = JSONUtil.parseObj(eosRes).getInt("code");
        if (0 != code) {
            throw new AppBusinessException("通知eos删除用户失败");
        }
        return eosRes;
    }

    /**
     * 重置用户角色
     *
     * @param userRoleDTO 用户信息
     * @return 重置结果
     */
    public String resetUserRole(UserRoleDTO userRoleDTO) {
        PtApp ptApp = ptAppService.getById(userRoleDTO.getAppId());
        Assert.notNull(ptApp, () -> {
            throw new AppBusinessException("不存在此应用");
        });
        String eosToken = EosTokenCache.getAuthToken();
        String eosRes = HttpRequest.put(updateUserRoleUrl)
                .body(JSONUtil.toJsonStr(userRoleDTO))
                .header("Authorization", eosToken)
                .header("Eos-Project", ptApp.getAuthCenterId())
                .execute().body();
        log.info("鉴权中心根据角色添加用户,参数:{},返回:{}", JSONUtil.toJsonStr(userRoleDTO), eosRes);
        Integer code = JSONUtil.parseObj(eosRes).getInt("code");
        if (0 != code) {
            throw new AppBusinessException("通知eos添加用户失败");
        }
        return eosRes;
    }

    /**
     * 根据角色导入用户
     *
     * @param file
     * @param appId
     */
    public void importUserRole(MultipartFile file, String appId) {
        PtApp ptApp = ptAppService.getById(appId);
        Assert.notNull(ptApp, () -> {
            throw new AppBusinessException("不存在此应用");
        });
        List<UserRoleDTO> userRoleDTOS;
        try {
            String listStr = commService.parseExcelByTemplate("IMPORT_USER", file);
            userRoleDTOS = JSONArray.parseArray(listStr, UserRoleDTO.class);
        } catch (Exception e) {
            log.error("文件解析错误：" + e);
            throw new AppBusinessException("文件解析错误");
        }
        Map<String, List<String>> roleMap = new HashMap<>();
        List<String> accountList;
        String account = null;
        try {
            account = CommonUtil.userHolder.get().getAccount();
        } catch (Exception e) {
            log.error("获取当前登录用户域账号报错");
        }

        List<EosRoleClientDTO> roleList = getRoleList(null, appId, 1, 999, account);
        List<String> roleCodeList = roleList.stream().map(EosRoleClientDTO::getRoleCode).collect(Collectors.toList());
        List<UserRoleDTO> userRoleDTOList = new ArrayList<>();
        String eosToken = commService.getAuthenticationCenterToken(eosAPassAccount, eosAPassPasswd);
        for (UserRoleDTO userRoleDTO : userRoleDTOS) {
            if (userRoleDTO.getRoleCode() == null || userRoleDTO.getWorkerId() == null) {
                continue;
            }
            userRoleDTO.setRoleCode(userRoleDTO.getRoleCode().trim());
            userRoleDTO.setWorkerId(userRoleDTO.getWorkerId().trim());
            userRoleDTOList.add(userRoleDTO);
        }
        for (UserRoleDTO userRoleDTO : userRoleDTOList) {
            if (!roleCodeList.contains(userRoleDTO.getRoleCode())) {
                continue;
            }
            PtAllWorker allWorker = ptAllWorkerService.getById(userRoleDTO.getWorkerId());

            if (!roleMap.containsKey(userRoleDTO.getRoleCode())) {
                accountList = new ArrayList<>();
                accountList.add(allWorker.getDomainAccount());
                roleMap.put(userRoleDTO.getRoleCode(), accountList);
            } else {
                List<String> accounts = roleMap.get(userRoleDTO.getRoleCode());
                accounts.add(allWorker.getDomainAccount());
                roleMap.put(userRoleDTO.getRoleCode(), accounts);
            }
        }
        for (String roleCode : roleMap.keySet()) {
            UserRoleDTO userRoleDTO = new UserRoleDTO();
            userRoleDTO.setRoleCode(roleCode);
            userRoleDTO.setAccountList(roleMap.get(roleCode));
            List<EosUserClientDTO> userList = getUserListByRoleCode(userRoleDTO.getRoleCode(), appId, 1, 999);
            //获取该角色下已存在的域账号集合
            List<String> accounts = userList.stream().map(EosUserClientDTO::getAccount).collect(Collectors.toList());
            //去除该角色中已存在的用户
            userRoleDTO.getAccountList().removeIf(accounts::contains);
            if (userRoleDTO.getAccountList().size() > 0) {
                String eosRes = HttpRequest.put(updateUserRoleUrl)
                        .body(JSONUtil.toJsonStr(userRoleDTO))
                        .header("Authorization", eosToken)
                        .header("Eos-Project", ptApp.getAuthCenterId())
                        .execute().body();
                log.info("批量导入授权用户，鉴权中心返回:{}", eosRes);
            }
        }
    }

    public List<String> getUserRoleByAccount(String account, String appId) {
        PtApp ptApp = ptAppService.getById(appId);
        Assert.notNull(ptApp, () -> {
            throw new AppBusinessException("不存在此应用");
        });
        String eosToken = commService.getAuthenticationCenterToken(eosAPassAccount, eosAPassPasswd);
        String eosRes = HttpRequest.get(queryUserRoleByAccount)
                .form("account", account)
                .header("Authorization", eosToken)
                .header("Eos-Project", ptApp.getAuthCenterId())
                .execute().body();
        if (JSONUtil.parseObj(eosRes).getInt("code").equals(0)) {
            return JSONUtil.parseObj(eosRes).getJSONArray("data").toList(String.class);
        }
        log.error("查询:{}用户角色报错:{}", account, eosRes);
        return new ArrayList<>();
    }

    /**
     * 获取用户的授权角色
     * @param account 域账号
     * @param appId 租户id
     * @return 用户的授权角色
     */
    public List<EosRoleClientDTO> getRolesByAccount(String account, String appId) {
        PtApp ptApp = ptAppService.getById(appId);
        Assert.notNull(ptApp, () -> {
            throw new AppBusinessException("不存在此应用");
        });
        String eosToken = commService.getAuthenticationCenterToken(eosAPassAccount, eosAPassPasswd);
        String eosRes = HttpRequest.get(getRolesByAccountUrl)
                .form("account", account)
                .header("Authorization", eosToken)
                .header("Eos-Project", ptApp.getAuthCenterId())
                .execute().body();
        if (JSONUtil.parseObj(eosRes).getInt("code").equals(0)) {
            List<EosRoleClientDTO> eosRoleList = JSONUtil.parseObj(eosRes).getJSONArray("data").toList(EosRoleClientDTO.class);
            if (CollectionUtils.isNotEmpty(eosRoleList)) {
                eosRoleList = eosRoleList.stream()
                        .filter(o -> Objects.equals(o.getRoleType(), "CUSTOM")
                                && !"AUTH_INITIAL_ADMIN".equals(o.getRoleCode()))
                        .collect(Collectors.toList());
                if ("hrdataboard".equals(appId)) {
                    return eosRoleList.stream().filter(s -> s.getRoleCode().contains("budget")).collect(Collectors.toList());
                } else if ("hr-dynamic-board".equals(appId)) {
                    return eosRoleList.stream().filter(s -> s.getRoleCode().contains("dynamic")).collect(Collectors.toList());
                } else if ("e-sign-platform".equals(appId)) {
                    List<String> roles = getUserRoleByAccount(account, appId);
                    boolean isSSC = false;
                    for (String role : roles) {
                        if (role.equals("SSC-SIGN")) {
                            isSSC = true;
                            break;
                        }
                    }
                    if (!isSSC) {
                        List<PtRoleUser> ptRoleUsers = roleUserMapper.selectList(new QueryWrapper<PtRoleUser>().lambda()
                                .eq(PtRoleUser::getAppId, appId)
                                .eq(PtRoleUser::getDomainAccount, account));
                        return eosRoleList.stream().filter((s) -> {
                            boolean match = false;
                            for (PtRoleUser roleUser : ptRoleUsers) {
                                if (roleUser.getRoleId().equals(s.getRoleCode())) {
                                    match = true;
                                    break;
                                }
                            }
                            return match;
                        }).collect(Collectors.toList());
                    }
                }
                return eosRoleList;
            }
        }
        log.error("查询:{}用户角色报错:{}", account, eosRes);
        return null;
    }

    public Map<String, Map<String, List<String>>> getUserByDeptAndRole(List<GetUserByDeptAndRoleBO> userByDeptAndRoleBO) {
        HashMap<String, Map<String, List<String>>> result = new HashMap<>(userByDeptAndRoleBO.size());
        for (GetUserByDeptAndRoleBO getUserByDeptAndRoleBO : userByDeptAndRoleBO) {
            PtUserDept userDept = ptUserDeptService.getOne(new QueryWrapper<PtUserDept>().lambda()
                    .eq(PtUserDept::getDeptId, getUserByDeptAndRoleBO.getDeptId())
                    .eq(PtUserDept::getAppId, getUserByDeptAndRoleBO.getAppId())
            );
            if (Objects.isNull(userDept) || StringUtils.isBlank(userDept.getUserIds())) {
                List<String> splitTrim = StrUtil.splitTrim(getUserByDeptAndRoleBO.getRoleCode(), ",");
                for (String role : splitTrim) {
                    Map map = MapUtil.get(result, getUserByDeptAndRoleBO.getDeptId(), Map.class, new HashMap<String, List<String>>(splitTrim.size()));
                    map.put(role, new ArrayList<>());
                    result.put(getUserByDeptAndRoleBO.getDeptId(), map);
                }
                continue;
            }
            String userIds = userDept.getUserIds();
            List<String> roleList = StrUtil.splitTrim(getUserByDeptAndRoleBO.getRoleCode(), ",");
            for (String role : roleList) {
                ArrayList<String> temp = new ArrayList<>();
                for (PtAllWorker ptAllWorker : ptAllWorkerService.listByIds(StrUtil.splitTrim(userIds, ","))) {
                    if (getUserRoleByAccount(ptAllWorker.getDomainAccount(), getUserByDeptAndRoleBO.getAppId()).contains(role)) {
                        temp.add(ptAllWorker.getWorkerId());
                    }
                }
                Map map = MapUtil.get(result, getUserByDeptAndRoleBO.getDeptId(), Map.class, new HashMap<String, List<String>>(roleList.size()));
                map.put(role, temp);
                result.put(getUserByDeptAndRoleBO.getDeptId(), map);
            }
        }
        return result;
    }

    public List<EosRoleClientDTO> getRoleListForSignPlatform(String query, String appId, String domain) {
        List<EosRoleClientDTO> allRoles = getRoleList(query, appId, 1, 500, null);
        HashMap<String, Object> params = new HashMap<>(4);
        params.put("pageNum", 1);
        params.put("pageSize", 500);
        params.put("searchType", 0);
        String eosToken = commService.getAuthenticationCenterToken(eosAPassAccount, eosAPassPasswd);
        return allRoles.stream().filter(role -> {
            List<EosUserClientDTO> list = getUserListByRoleCode(role.getRoleCode(), appId, eosToken, params);
            boolean flag = false;
            for (EosUserClientDTO user : list) {
                if (user.getAccount().equals(domain)) {
                    flag = true;
                    break;
                }
            }
            return flag;
        }).collect(Collectors.toList());
    }


}
